#ifdef __arm__
#ifndef __aarch64__
    .text
    .align  5
    //.p2align 5,,15
    .global ConvInt16Unit
#ifndef __APPLE__
    .type   ConvInt16Unit, %function
#endif

.macro INIT_ZERO
    // we could also use "vmov.s32 q12, #0" to initialize q12 by 0
    veor.s32 q8, q8, q8
    veor.s32 q9, q9, q9
    veor.s32 q10, q10, q10
    veor.s32 q11, q11, q11
    veor.s32 q12, q12, q12
    veor.s32 q13, q13, q13
    veor.s32 q14, q14, q14
    veor.s32 q15, q15, q15
.endm

// void ConvInt16Unit(input, weight, output, ic8, oc4);
// r0: input, r1: weight, r2: output, r3, ic8, r4: oc4
ConvInt16Unit:
    // at return, clang generates "push {lr}, pop {pc}"" while gcc will generate "bx lr"
    // according to https://stackoverflow.com/questions/53625807
    // even if we jump to link register instead of saving it, we still have to save it in subroutine calls anyway
    // clang's rule seems more simple, though there are no subroutine calls here
    // r4-r8 and q4-q7 must be saved according to https://static.docs.arm.com/ihi0042/i/aapcs32.pdf
    push {r4-r8, lr}

    ldr r4, [sp, #24]

    vpush {q4-q7}

    LoopStart:
        mov r7, r0
        mov r6, #8
    
        LoopKw:

            INIT_ZERO

            vld1.s16 {q0}, [r7]!
            vld1.s16 {q4, q5}, [r1]!
            vmlal.s16 q8, d0, d18
            vmlal.s16 q8, d1, d19
            vld1.s16 {q6, q7}, [r1]!

            subs r5, r3, #1
            beq LoopIcEnd

            LoopIc:
                vmlal.s16 q9, d0, d10
                vmlal.s16 q9, d1, d11
                vld1.s16 {q1}, [r7]!
                vmlal.s16 q10, d0, d12
                vmlal.s16 q10, d1, d13
                vld1.s16 {q4, q5}, [r1]!
                vmlal.s16 q11, d0, d14
                vmlal.s16 q11, d1, d15
                vld1.s16 {q6, q7}, [r1]!
                vmlal.s16 q12, d2, d8
                vmlal.s16 q12, d3, d9
                vld1.s16 {q0}, [r7]!
                vmlal.s16 q13, d2, d10
                vmlal.s16 q13, d3, d11
                vld1.s16 {q4, q5}, [r1]!
                vmlal.s16 q14, d2, d12
                vmlal.s16 q14, d3, d13
                vmlal.s16 q15, d2, d14
                vmlal.s16 q15, d3, d15
                vld1.s16 {q6, q7}, [r1]!
                vmlal.s16 q8, d0, d8
                vmlal.s16 q8, d1, d9

                subs r5, r5, #1
                bne LoopIc
        
            LoopIcEnd:
                vmlal.s16 q9, d0, d10
                vmlal.s16 q9, d1, d11
                vld1.s16 {q1}, [r7]!
                vmlal.s16 q10, d0, d12
                vmlal.s16 q10, d1, d13
                vld1.s16 {q4, q5}, [r1]!
                vmlal.s16 q11, d0, d14
                vmlal.s16 q11, d1, d15
                vld1.s16 {q6, q7}, [r1]!
                vmlal.s16 q12, d2, d8
                vmlal.s16 q12, d3, d9
                vmlal.s16 q13, d2, d10
                vmlal.s16 q13, d3, d11
                vmlal.s16 q14, d2, d12
                vmlal.s16 q14, d3, d13
                vmlal.s16 q15, d2, d14
                vmlal.s16 q15, d3, d15

            vpadd.s32 d16, d16, d17
            vpadd.s32 d18, d18, d19
            vpadd.s32 d20, d20, d21
            vpadd.s32 d22, d22, d23
            vpadd.s32 d4, d16, d18
            vpadd.s32 d5, d20, d22

            vpadd.s32 d24, d24, d25
            vpadd.s32 d26, d26, d27
            vpadd.s32 d28, d28, d29
            vpadd.s32 d30, d30, d31
            vpadd.s32 d6, d24, d26
            vpadd.s32 d7, d28, d30

            vst1.s32 {q2, q3}, [r2]!

            subs r6, r6, #1
            bne LoopKw

        subs r4, r4, #1
        bne LoopStart

    vpop {q4-q7}
    pop {r4, r5, r6, r7, r8, pc}

#endif
#endif
